/* A packrat parser generated by PackCC 1.5.0 */

#ifdef _MSC_VER
#undef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif /* _MSC_VER */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef _MSC_VER
#if defined __GNUC__ && defined _WIN32	/* MinGW */
#ifndef PCC_USE_SYSTEM_STRNLEN
#define strnlen(str, maxlen) pcc_strnlen(str, maxlen)
static size_t pcc_strnlen(const char *str, size_t maxlen)
{
	size_t i;
	for (i = 0; i < maxlen && str[i]; i++) ;
	return i;
}
#endif /* !PCC_USE_SYSTEM_STRNLEN */
#endif /* defined __GNUC__ && defined _WIN32 */
#endif /* !_MSC_VER */

#define PCC_DBG_EVALUATE 0
#define PCC_DBG_MATCH    1
#define PCC_DBG_NOMATCH  2

#include "gml.h"

#include "config.h"

#include <stdio.h>
#include <string.h>
#include <errno.h>

#include "main.h"
#include "mem.h"
#include "uniqstring.h"
#include "uniqnode.h"

static struct usrgraph *maing = NULL;

/* different block modes */
#define INHUH 0			/* unknown */
#define INNODE 1		/* node [...] */
#define INEDGE 2		/* edge [...] */
#define INGRAPHICS 3		/* graphics [...] */

static int cmode1 = INHUH;
static int cmode2 = INHUH;

static FILE *curstream = NULL;

#define PCC_BUFFERSIZE 2048
#define PCC_ARRAYSIZE 16

#undef strnlen
#define strnlen(str, maxlen) pcc_strnlen(str, maxlen)
static size_t pcc_strnlen(const char *str, size_t maxlen)
{
	size_t i;
	for (i = 0; i < maxlen && str[i]; i++) ;
	return i;
}

#define PCC_MALLOC(auxil, size) pcc_malloc_e(size)
static void *pcc_malloc_e(size_t size)
{
	void *p = calloc(1, size);
	if (p == NULL) {
		exit(1);
	}
	return p;
}

#define PCC_FREE(auxil, ptr) if (ptr) { free(ptr); }

#define PCC_REALLOC(auxil, ptr, size) realloc(ptr, size)

/* node id */
static char *nodeid = NULL;

/* node label */
static char *nodelabel = NULL;

/* edge from */
static char *edgefrom = NULL;

/* edge to */
static char *edgeto = NULL;

/* edge label */
static char *edgelabel = NULL;

/* edge fill */
static char *efill = NULL;

/* node fill */
static char *nfill = NULL;

/* current fill */
static char *currfill = NULL;

/* node outline */
static char *noutline = NULL;

/* current outline */
static char *curroutline = NULL;

static char *pname = "";

static int ind = 0;

static int parseerror = 0;

static int linenr = 1;

static int pdebug = 0;

static const char *dbg_str[] = { "Evaluating rule", "Matched rule", "Abandoning rule" };

#define PCC_DEBUG(event, rule, level, pos, buffer, length) \
    if (pdebug) { fprintf(stdout, "%*s%s %s @%d [%.*s]\n", (int)(level * 2), "", dbg_str[event], rule, (int)pos, (int)length,  buffer); fflush(stdout); }

#define PCC_ERROR(auxil) { pcc_error(); return 0; }

static void pcc_error(void)
{
	printf("Gml graph syntax error at line %d in file %s\n", linenr, pname);
	parseerror = 1;
	return;
}

#define PCC_GETCHAR(auxil) myfgetc()

/* return EOF at parse error to stop parser or next char from stream */
static int myfgetc(void)
{
	int ret = 0;
	if (parseerror) {
		/* return EOF at parse error */
		ret = EOF;
	} else {
		/* no parse error, get next char */
		ret = fgetc(curstream);
		if (pdebug) {
			if (ret > 0 && ret != EOF) {
				printf("/* %c */\n", ret);
			}
		}
		if (ret == '\n') {
			linenr++;
		}
	}
	return (ret);
}

/* at start of "id [...]" */
static void start(int ix, char *str)
{
	if (ix == 2) {
		if (strcmp(str, "graphics") == 0) {
			if (cmode1 == INNODE || cmode1 == INEDGE) {
				cmode2 = INGRAPHICS;
				currfill = NULL;
				curroutline = NULL;
			} else {
				cmode2 = INHUH;
			}
		} else {
			cmode2 = INHUH;
		}
		return;
	}
	if (ix == 1) {
		cmode2 = INHUH;
		if (strcmp(str, "node") == 0) {
			cmode1 = INNODE;
			nodeid = NULL;
			nodelabel = NULL;
			nfill = NULL;
			noutline = NULL;
			currfill = NULL;
			curroutline = NULL;
		} else if (strcmp(str, "edge") == 0) {
			cmode1 = INEDGE;
			edgefrom = NULL;
			edgeto = NULL;
			edgelabel = NULL;
			efill = NULL;
			currfill = NULL;
		} else {
			cmode1 = INHUH;
		}
		return;
	}
	return;
}

/* #rrggbb to int */
static int color2int(char *str)
{
	int status = 0;
	int ret = -1;
	unsigned int r = 0;
	unsigned int g = 0;
	unsigned int b = 0;
	errno = 0;
	if (str == NULL) {
		printf("expected html color in form of \"#rrggbb\" but found nil\n");
		return (-1);
	}
	if (strlen(str) == 0) {
		printf("expected html color in form of \"#rrggbb\" but found \"\"\n");
		return (-1);
	}
	status = sscanf(str, "#%02x%02x%02x", &r, &g, &b);
	if (status == 3) {
		ret = ((r << 16) | (g << 8) | b);
	} else if (errno != 0) {
		/* convers error */
		ret = -1;
	} else {
		/* did not match */
		ret = -1;
	}
	if (ret == -1) {
		printf("expected html color in form of #rrggbb but found %s\n", str);
	}
	return (ret);
}

/* */
static int str2num(char *str)
{
	long int r = 0;
	char *es;
	errno = 0;
	if (str == NULL) {
		errno = EINVAL;
		return (0);
	}
	if (strlen(str) == 0) {
		errno = EINVAL;
		return (0);
	}
	r = strtol(str, &es, 10);
	if (str == es) {
		errno = EINVAL;
		return (0);
	}
	return ((int)r);
}

/* add node */
static void nadd(char *nid, char *nl, char *nf, char *no)
{
	char *nl2 = NULL;
	char *nf2 = NULL;
	char *no2 = NULL;
	int nfcol = 0xffffff;
	int nocol = 0;
	int nidnum = 0;
	struct usrnode *nun = NULL;
	struct usrnode *nun2 = NULL;
	if (nl) {
		if (strlen(nl)) {
			nl2 = nl;
		} else {
			nl2 = NULL;
		}
	}
	if (nf) {
		if (strlen(nf)) {
			nf2 = nf;
		} else {
			nf2 = NULL;
		}
	}
	if (no) {
		if (strlen(no)) {
			no2 = no;
		} else {
			no2 = NULL;
		}
	}
	if (nf2) {
		nfcol = color2int(nf2);
		if (nfcol == -1) {
			printf("unknown node fill color %s skipped\n", nf2);
			nfcol = 0xffffff;
		}
	}
	if (no2) {
		nocol = color2int(no2);
		if (nocol == -1) {
			printf("unknown node outline color %s skipped\n", no2);
			nocol = 0;
		}
	}
	nidnum = str2num(nid);
	if (errno) {
		printf("wrong number %s for node id and node skipped\n", nid);
		errno = 0;
		return;
	}
	if (pdebug) {
		printf("adding node %s, label %s, fillcolor %s outline color %s\n", nid, nl2, nf2, no2);
	}
	/* check if already defined */
	nun = uniqnode_gid(nidnum);
	if (nun) {
		printf("node with id %s is already defined and replacing it\n", nid);
		nun2 = nun;
	} else {
		nun = do_malloc(sizeof(struct usrnode));
	}
	nun->gmlid = nidnum;
	nun->gmlidstr = nid;
	nun->fill = nf2;
	nun->fillcolor = nfcol;
	nun->outline = no2;
	nun->outlinecolor = nocol;
	if (nl2) {
		nun->nlabel = nl2;
	} else {
		nun->nlabel = nun->gmlidstr;
	}
	if (nun2 == NULL) {
		if (maing->rawnodelist == NULL) {
			maing->rawnodelist = nun;
			maing->rawnodelistend = nun;
		} else {
			maing->rawnodelistend->next = nun;
			maing->rawnodelistend = nun;
		}
		uniqnode_gid_add(nun);
	}
	return;
}

/* add edge */
static void eadd(char *ef, char *et, char *el, char *efil)
{
	char *el2 = NULL;
	char *efil2 = NULL;
	int ecol = 0;
	int efnum = 0;
	int etnum = 0;
	struct usrnode *nunf = NULL;
	struct usrnode *nunt = NULL;
	struct usredge *ned = NULL;
	if (el) {
		if (strlen(el)) {
			el2 = el;
		} else {
			el2 = NULL;
		}
	}
	if (efil) {
		if (strlen(efil)) {
			efil2 = efil;
		} else {
			efil2 = NULL;
		}
	}
	if (efil2) {
		ecol = color2int(efil2);
		if (ecol == -1) {
			printf("unknown edge color %s skipped\n", efil2);
			ecol = 0;
		}
	}
	efnum = str2num(ef);
	if (errno) {
		printf("wrong number %s for edge source id and edge skipped\n", ef);
		errno = 0;
		return;
	}
	etnum = str2num(et);
	if (errno) {
		printf("wrong number %s for edge target id and edge skipped\n", et);
		errno = 0;
		return;
	}
	if (pdebug) {
		printf("adding edge from %s to %s, label %s, edge line color %s\n", ef, et, el2, efil2);
	}
	/* check if already defined */
	nunf = uniqnode_gid(efnum);
	if (nunf == NULL) {
		printf("source node %d in edge from %s to %s not found and adding source node now\n", efnum, ef, et);
		nadd(ef, NULL, NULL, NULL);
		nunf = uniqnode_gid(efnum);
	}
	/* check if already defined */
	nunt = uniqnode_gid(etnum);
	if (nunt == NULL) {
		printf("target node %d in edge from %s to %s not found and adding source node now\n", etnum, ef, et);
		nadd(et, NULL, NULL, NULL);
		nunt = uniqnode_gid(etnum);
	}
	ned = do_malloc(sizeof(struct usredge));
	ned->fromgmlid = efnum;
	ned->togmlid = etnum;
	ned->fill = efil2;
	ned->fillcolor = ecol;
	ned->elabel = el2;
	if (maing->rawedgelist == NULL) {
		maing->rawedgelist = ned;
		maing->rawedgelistend = ned;
	} else {
		maing->rawedgelistend->next = ned;
		maing->rawedgelistend = ned;
	}
	return;
}

/* at end of "id [...]" */
static void fin(int ix)
{
	if (ix == 1) {
		if (cmode1 == INNODE) {
			nadd(nodeid, nodelabel, nfill, noutline);
		} else if (cmode1 == INEDGE) {
			eadd(edgefrom, edgeto, edgelabel, efill);
		} else {
			/* skip */
		}
		return;
	}
	if (ix == 2) {
		if (cmode2 == INGRAPHICS) {
			if (cmode1 == INNODE) {
				if (currfill) {
					nfill = currfill;
				}
				if (curroutline) {
					noutline = curroutline;
				}
			} else if (cmode1 == INEDGE) {
				if (currfill) {
					efill = currfill;
				}
			} else {
				/* skip */
			}
		}
		return;
	}
	return;
}

/* id id */
static void pair_ii(char *l, char *r, int ix)
{
	return;
}

/* id string and "" for r is same as NULL */
static void pair_is(char *l, char *r, int ix)
{
	if (ix == 1) {
		if (cmode1 == INNODE) {
			if (strcmp(l, "label") == 0) {
				if (nodelabel) {
					printf("redefinition of node label from %s to %s\n", nodelabel, r);
				}
				nodelabel = r;
			}
		} else if (cmode1 == INEDGE) {
			if (strcmp(l, "label") == 0) {
				if (edgelabel) {
					printf("redefinition of edge label from %s to %s\n", edgelabel, r);
				}
				edgelabel = r;
			}
		} else {
			/* skip */
		}
		return;
	}
	if (ix == 2) {
		if (cmode2 == INGRAPHICS) {
			if (cmode1 == INNODE) {
				if (strcmp(l, "fill") == 0) {
					if (currfill) {
						printf("redefinition of node fill from %s to %s\n", currfill, r);
					}
					currfill = r;
				} else if (strcmp(l, "outline") == 0) {
					if (curroutline) {
						printf("redefinition of node outline from %s to %s\n", curroutline, r);
					}
					curroutline = r;
				} else {
					/* skip */
				}
			} else if (cmode1 == INEDGE) {
				if (strcmp(l, "fill") == 0) {
					if (currfill) {
						printf("redefinition of edge fill from %s to %s\n", currfill, r);
					}
					currfill = r;
				} else {
					/* skip */
				}
			} else {
				/* skip */
			}
		}
		return;
	}
	return;
}

/* id fpnum */
static void pair_if(char *l, char *r, int ix)
{
	return;
}

/* id num */
static void pair_id(char *l, char *r, int ix)
{
	if (ix == 1) {
		if (cmode1 == INNODE) {
			if (strcmp(l, "id") == 0) {
				if (nodeid) {
					printf("redefinition of node id from %s to %s\n", nodeid, r);
				}
				nodeid = r;
			}
		} else if (cmode1 == INEDGE) {
			if (strcmp(l, "source") == 0) {
				if (edgefrom) {
					printf("redefinition of edge source from %s to %s\n", edgefrom, r);
				}
				edgefrom = r;
			} else if (strcmp(l, "target") == 0) {
				if (edgeto) {
					printf("redefinition of edge target from %s to %s\n", edgeto, r);
				}
				edgeto = r;
			} else {
				/* skip */
			}
		} else {
			/* skip */
		}
		return;
	}
	return;
}

#ifndef PCC_BUFFERSIZE
#define PCC_BUFFERSIZE 256
#endif /* !PCC_BUFFERSIZE */

#ifndef PCC_ARRAYSIZE
#define PCC_ARRAYSIZE 2
#endif /* !PCC_ARRAYSIZE */

#define VOID_VALUE (~(size_t)0)

typedef enum pcc_bool_tag {
	PCC_FALSE = 0,
	PCC_TRUE
} pcc_bool_t;

typedef struct pcc_char_array_tag {
	char *buf;
	size_t max;
	size_t len;
} pcc_char_array_t;

typedef struct pcc_range_tag {
	size_t start;
	size_t end;
} pcc_range_t;

typedef char *pcc_value_t;

typedef void *pcc_auxil_t;

typedef struct pcc_value_table_tag {
	pcc_value_t *buf;
	size_t max;
	size_t len;
} pcc_value_table_t;

typedef struct pcc_value_refer_table_tag {
	pcc_value_t **buf;
	size_t max;
	size_t len;
} pcc_value_refer_table_t;

typedef struct pcc_capture_tag {
	pcc_range_t range;
	char *string;		/* mutable */
} pcc_capture_t;

typedef struct pcc_capture_table_tag {
	pcc_capture_t *buf;
	size_t max;
	size_t len;
} pcc_capture_table_t;

typedef struct pcc_capture_const_table_tag {
	const pcc_capture_t **buf;
	size_t max;
	size_t len;
} pcc_capture_const_table_t;

typedef struct pcc_thunk_tag pcc_thunk_t;
typedef struct pcc_thunk_array_tag pcc_thunk_array_t;

typedef void (*pcc_action_t)(gml_context_t *, pcc_thunk_t *, pcc_value_t *);

typedef enum pcc_thunk_type_tag {
	PCC_THUNK_LEAF,
	PCC_THUNK_NODE
} pcc_thunk_type_t;

typedef struct pcc_thunk_leaf_tag {
	pcc_value_refer_table_t values;
	pcc_capture_const_table_t capts;
	pcc_capture_t capt0;
	pcc_action_t action;
} pcc_thunk_leaf_t;

typedef struct pcc_thunk_node_tag {
	const pcc_thunk_array_t *thunks;	/* just a reference */
	pcc_value_t *value;	/* just a reference */
} pcc_thunk_node_t;

typedef union pcc_thunk_data_tag {
	pcc_thunk_leaf_t leaf;
	pcc_thunk_node_t node;
} pcc_thunk_data_t;

struct pcc_thunk_tag {
	pcc_thunk_type_t type;
	pcc_thunk_data_t data;
};

struct pcc_thunk_array_tag {
	pcc_thunk_t **buf;
	size_t max;
	size_t len;
};

typedef struct pcc_thunk_chunk_tag {
	pcc_value_table_t values;
	pcc_capture_table_t capts;
	pcc_thunk_array_t thunks;
	size_t pos;		/* the starting position in the character buffer */
} pcc_thunk_chunk_t;

typedef struct pcc_lr_entry_tag pcc_lr_entry_t;

typedef enum pcc_lr_answer_type_tag {
	PCC_LR_ANSWER_LR,
	PCC_LR_ANSWER_CHUNK
} pcc_lr_answer_type_t;

typedef union pcc_lr_answer_data_tag {
	pcc_lr_entry_t *lr;
	pcc_thunk_chunk_t *chunk;
} pcc_lr_answer_data_t;

typedef struct pcc_lr_answer_tag pcc_lr_answer_t;

struct pcc_lr_answer_tag {
	pcc_lr_answer_type_t type;
	pcc_lr_answer_data_t data;
	size_t pos;		/* the absolute position in the input */
	pcc_lr_answer_t *hold;
};

typedef pcc_thunk_chunk_t *(*pcc_rule_t)(gml_context_t *);

typedef struct pcc_rule_set_tag {
	pcc_rule_t *buf;
	size_t max;
	size_t len;
} pcc_rule_set_t;

typedef struct pcc_lr_head_tag pcc_lr_head_t;

struct pcc_lr_head_tag {
	pcc_rule_t rule;
	pcc_rule_set_t invol;
	pcc_rule_set_t eval;
	pcc_lr_head_t *hold;
};

typedef struct pcc_lr_memo_tag {
	pcc_rule_t rule;
	pcc_lr_answer_t *answer;
} pcc_lr_memo_t;

typedef struct pcc_lr_memo_map_tag {
	pcc_lr_memo_t *buf;
	size_t max;
	size_t len;
} pcc_lr_memo_map_t;

typedef struct pcc_lr_table_entry_tag {
	pcc_lr_head_t *head;	/* just a reference */
	pcc_lr_memo_map_t memos;
	pcc_lr_answer_t *hold_a;
	pcc_lr_head_t *hold_h;
} pcc_lr_table_entry_t;

typedef struct pcc_lr_table_tag {
	pcc_lr_table_entry_t **buf;
	size_t max;
	size_t len;
} pcc_lr_table_t;

struct pcc_lr_entry_tag {
	pcc_rule_t rule;
	pcc_thunk_chunk_t *seed;	/* just a reference */
	pcc_lr_head_t *head;	/* just a reference */
};

typedef struct pcc_lr_stack_tag {
	pcc_lr_entry_t **buf;
	size_t max;
	size_t len;
} pcc_lr_stack_t;

struct gml_context_tag {
	size_t pos;		/* the position in the input of the first character currently buffered */
	size_t cur;		/* the current parsing position in the character buffer */
	size_t level;
	pcc_char_array_t buffer;
	pcc_lr_table_t lrtable;
	pcc_lr_stack_t lrstack;
	pcc_auxil_t auxil;
};

#ifndef PCC_ERROR
#define PCC_ERROR(auxil) pcc_error()
static void pcc_error(void)
{
	fprintf(stderr, "Syntax error\n");
	exit(1);
}
#endif /* !PCC_ERROR */

#ifndef PCC_GETCHAR
#define PCC_GETCHAR(auxil) getchar()
#endif /* !PCC_GETCHAR */

#ifndef PCC_MALLOC
#define PCC_MALLOC(auxil, size) pcc_malloc_e(size)
static void *pcc_malloc_e(size_t size)
{
	void *const p = malloc(size);
	if (p == NULL) {
		fprintf(stderr, "Out of memory\n");
		exit(1);
	}
	return p;
}
#endif /* !PCC_MALLOC */

#ifndef PCC_REALLOC
#define PCC_REALLOC(auxil, ptr, size) pcc_realloc_e(ptr, size)
static void *pcc_realloc_e(void *ptr, size_t size)
{
	void *const p = realloc(ptr, size);
	if (p == NULL) {
		fprintf(stderr, "Out of memory\n");
		exit(1);
	}
	return p;
}
#endif /* !PCC_REALLOC */

#ifndef PCC_FREE
#define PCC_FREE(auxil, ptr) free(ptr)
#endif /* !PCC_FREE */

#ifndef PCC_DEBUG
#define PCC_DEBUG(event, rule, level, pos, buffer, length) ((void)0)
#endif /* !PCC_DEBUG */

static char *pcc_strndup_e(pcc_auxil_t auxil, const char *str, size_t len)
{
	const size_t m = strnlen(str, len);
	char *const s = (char *)PCC_MALLOC(auxil, m + 1);
	if (auxil) {
	}
	memcpy(s, str, m);
	s[m] = '\0';
	return s;
}

static void pcc_char_array__init(pcc_auxil_t auxil, pcc_char_array_t * array, size_t max)
{
	array->len = 0;
	array->max = max;
	if (auxil) {
	}
	array->buf = (char *)PCC_MALLOC(auxil, array->max);
}

static void pcc_char_array__add(pcc_auxil_t auxil, pcc_char_array_t * array, char ch)
{
	if (array->max <= array->len) {
		const size_t n = array->len + 1;
		size_t m = array->max;
		if (m == 0)
			m = 1;
		while (m < n && m != 0)
			m <<= 1;
		if (m == 0)
			m = n;
		if (auxil) {
		}
		array->buf = (char *)PCC_REALLOC(auxil, array->buf, m);
		array->max = m;
	}
	array->buf[array->len++] = ch;
}

static void pcc_char_array__term(pcc_auxil_t auxil, pcc_char_array_t * array)
{
	PCC_FREE(auxil, array->buf);
}

static void pcc_value_table__init(pcc_auxil_t auxil, pcc_value_table_t * table, size_t max)
{
	table->len = 0;
	table->max = max;
	table->buf = (pcc_value_t *) PCC_MALLOC(auxil, sizeof(pcc_value_t) * table->max);
	if (auxil) {
	}
	return;
}

static void pcc_value_table__resize(pcc_auxil_t auxil, pcc_value_table_t * table, size_t len)
{
	if (table->max < len) {
		size_t m = table->max;
		if (m == 0)
			m = 1;
		while (m < len && m != 0)
			m <<= 1;
		if (m == 0)
			m = len;
		table->buf = (pcc_value_t *) PCC_REALLOC(auxil, table->buf, sizeof(pcc_value_t) * m);
		table->max = m;
	}
	table->len = len;
}

static void pcc_value_table__term(pcc_auxil_t auxil, pcc_value_table_t * table)
{
	PCC_FREE(auxil, table->buf);
}

static void pcc_value_refer_table__init(pcc_auxil_t auxil, pcc_value_refer_table_t * table, size_t max)
{
	table->len = 0;
	table->max = max;
	table->buf = (pcc_value_t **) PCC_MALLOC(auxil, sizeof(pcc_value_t *) * table->max);
}

static void pcc_value_refer_table__resize(pcc_auxil_t auxil, pcc_value_refer_table_t * table, size_t len)
{
	size_t i;
	if (table->max < len) {
		size_t m = table->max;
		if (m == 0)
			m = 1;
		while (m < len && m != 0)
			m <<= 1;
		if (m == 0)
			m = len;
		table->buf = (pcc_value_t **) PCC_REALLOC(auxil, table->buf, sizeof(pcc_value_t *) * m);
		table->max = m;
	}
	for (i = table->len; i < len; i++)
		table->buf[i] = NULL;
	table->len = len;
}

static void pcc_value_refer_table__term(pcc_auxil_t auxil, pcc_value_refer_table_t * table)
{
	PCC_FREE(auxil, table->buf);
}

static void pcc_capture_table__init(pcc_auxil_t auxil, pcc_capture_table_t * table, size_t max)
{
	table->len = 0;
	table->max = max;
	table->buf = (pcc_capture_t *) PCC_MALLOC(auxil, sizeof(pcc_capture_t) * table->max);
}

static void pcc_capture_table__resize(pcc_auxil_t auxil, pcc_capture_table_t * table, size_t len)
{
	size_t i;
	for (i = len; i < table->len; i++)
		PCC_FREE(auxil, table->buf[i].string);
	if (table->max < len) {
		size_t m = table->max;
		if (m == 0)
			m = 1;
		while (m < len && m != 0)
			m <<= 1;
		if (m == 0)
			m = len;
		table->buf = (pcc_capture_t *) PCC_REALLOC(auxil, table->buf, sizeof(pcc_capture_t) * m);
		table->max = m;
	}
	for (i = table->len; i < len; i++) {
		table->buf[i].range.start = 0;
		table->buf[i].range.end = 0;
		table->buf[i].string = NULL;
	}
	table->len = len;
}

static void pcc_capture_table__term(pcc_auxil_t auxil, pcc_capture_table_t * table)
{
	while (table->len > 0) {
		table->len--;
		PCC_FREE(auxil, table->buf[table->len].string);
	}
	PCC_FREE(auxil, table->buf);
}

static void pcc_capture_const_table__init(pcc_auxil_t auxil, pcc_capture_const_table_t * table, size_t max)
{
	table->len = 0;
	table->max = max;
	table->buf = (const pcc_capture_t **)PCC_MALLOC(auxil, sizeof(const pcc_capture_t *) * table->max);
}

static void pcc_capture_const_table__resize(pcc_auxil_t auxil, pcc_capture_const_table_t * table, size_t len)
{
	size_t i;
	if (table->max < len) {
		size_t m = table->max;
		if (m == 0)
			m = 1;
		while (m < len && m != 0)
			m <<= 1;
		if (m == 0)
			m = len;
		table->buf =
		    (const pcc_capture_t **)PCC_REALLOC(auxil, (pcc_capture_t **) table->buf, sizeof(const pcc_capture_t *) * m);
		table->max = m;
	}
	for (i = table->len; i < len; i++)
		table->buf[i] = NULL;
	table->len = len;
}

static void pcc_capture_const_table__term(pcc_auxil_t auxil, pcc_capture_const_table_t * table)
{
	PCC_FREE(auxil, table->buf);
}

static pcc_thunk_t *pcc_thunk__create_leaf(pcc_auxil_t auxil, pcc_action_t action, size_t valuec, size_t captc)
{
	pcc_thunk_t *const thunk = (pcc_thunk_t *) PCC_MALLOC(auxil, sizeof(pcc_thunk_t));
	thunk->type = PCC_THUNK_LEAF;
	pcc_value_refer_table__init(auxil, &thunk->data.leaf.values, valuec);
	pcc_value_refer_table__resize(auxil, &thunk->data.leaf.values, valuec);
	pcc_capture_const_table__init(auxil, &thunk->data.leaf.capts, captc);
	pcc_capture_const_table__resize(auxil, &thunk->data.leaf.capts, captc);
	thunk->data.leaf.capt0.range.start = 0;
	thunk->data.leaf.capt0.range.end = 0;
	thunk->data.leaf.capt0.string = NULL;
	thunk->data.leaf.action = action;
	return thunk;
}

static pcc_thunk_t *pcc_thunk__create_node(pcc_auxil_t auxil, const pcc_thunk_array_t * thunks, pcc_value_t * value)
{
	pcc_thunk_t *const thunk = (pcc_thunk_t *) PCC_MALLOC(auxil, sizeof(pcc_thunk_t));
	thunk->type = PCC_THUNK_NODE;
	thunk->data.node.thunks = thunks;
	thunk->data.node.value = value;
	return thunk;
}

static void pcc_thunk__destroy(pcc_auxil_t auxil, pcc_thunk_t * thunk)
{
	if (thunk == NULL)
		return;
	switch (thunk->type) {
	case PCC_THUNK_LEAF:
		PCC_FREE(auxil, thunk->data.leaf.capt0.string);
		pcc_capture_const_table__term(auxil, &thunk->data.leaf.capts);
		pcc_value_refer_table__term(auxil, &thunk->data.leaf.values);
		break;
	case PCC_THUNK_NODE:
		break;
	default:		/* unknown */
		break;
	}
	PCC_FREE(auxil, thunk);
}

static void pcc_thunk_array__init(pcc_auxil_t auxil, pcc_thunk_array_t * array, size_t max)
{
	array->len = 0;
	array->max = max;
	array->buf = (pcc_thunk_t **) PCC_MALLOC(auxil, sizeof(pcc_thunk_t *) * array->max);
}

static void pcc_thunk_array__add(pcc_auxil_t auxil, pcc_thunk_array_t * array, pcc_thunk_t * thunk)
{
	if (array->max <= array->len) {
		const size_t n = array->len + 1;
		size_t m = array->max;
		if (m == 0)
			m = 1;
		while (m < n && m != 0)
			m <<= 1;
		if (m == 0)
			m = n;
		array->buf = (pcc_thunk_t **) PCC_REALLOC(auxil, array->buf, sizeof(pcc_thunk_t *) * m);
		array->max = m;
	}
	array->buf[array->len++] = thunk;
}

static void pcc_thunk_array__revert(pcc_auxil_t auxil, pcc_thunk_array_t * array, size_t len)
{
	while (array->len > len) {
		array->len--;
		pcc_thunk__destroy(auxil, array->buf[array->len]);
	}
}

static void pcc_thunk_array__term(pcc_auxil_t auxil, pcc_thunk_array_t * array)
{
	while (array->len > 0) {
		array->len--;
		pcc_thunk__destroy(auxil, array->buf[array->len]);
	}
	PCC_FREE(auxil, array->buf);
}

static pcc_thunk_chunk_t *pcc_thunk_chunk__create(pcc_auxil_t auxil)
{
	pcc_thunk_chunk_t *const chunk = (pcc_thunk_chunk_t *) PCC_MALLOC(auxil, sizeof(pcc_thunk_chunk_t));
	pcc_value_table__init(auxil, &chunk->values, PCC_ARRAYSIZE);
	pcc_capture_table__init(auxil, &chunk->capts, PCC_ARRAYSIZE);
	pcc_thunk_array__init(auxil, &chunk->thunks, PCC_ARRAYSIZE);
	chunk->pos = 0;
	return chunk;
}

static void pcc_thunk_chunk__destroy(pcc_auxil_t auxil, pcc_thunk_chunk_t * chunk)
{
	if (chunk == NULL)
		return;
	pcc_thunk_array__term(auxil, &chunk->thunks);
	pcc_capture_table__term(auxil, &chunk->capts);
	pcc_value_table__term(auxil, &chunk->values);
	PCC_FREE(auxil, chunk);
}

static void pcc_rule_set__init(pcc_auxil_t auxil, pcc_rule_set_t * set, size_t max)
{
	set->len = 0;
	set->max = max;
	set->buf = (pcc_rule_t *) PCC_MALLOC(auxil, sizeof(pcc_rule_t) * set->max);
}

static size_t pcc_rule_set__index(pcc_auxil_t auxil, const pcc_rule_set_t * set, pcc_rule_t rule)
{
	size_t i;
	for (i = 0; i < set->len; i++) {
		if (set->buf[i] == rule)
			return i;
	}
	return VOID_VALUE;
}

static pcc_bool_t pcc_rule_set__add(pcc_auxil_t auxil, pcc_rule_set_t * set, pcc_rule_t rule)
{
	const size_t i = pcc_rule_set__index(auxil, set, rule);
	if (i != VOID_VALUE)
		return PCC_FALSE;
	if (set->max <= set->len) {
		const size_t n = set->len + 1;
		size_t m = set->max;
		if (m == 0)
			m = 1;
		while (m < n && m != 0)
			m <<= 1;
		if (m == 0)
			m = n;
		set->buf = (pcc_rule_t *) PCC_REALLOC(auxil, set->buf, sizeof(pcc_rule_t) * m);
		set->max = m;
	}
	set->buf[set->len++] = rule;
	return PCC_TRUE;
}

static pcc_bool_t pcc_rule_set__remove(pcc_auxil_t auxil, pcc_rule_set_t * set, pcc_rule_t rule)
{
	const size_t i = pcc_rule_set__index(auxil, set, rule);
	if (i == VOID_VALUE)
		return PCC_FALSE;
	memmove(set->buf + i, set->buf + (i + 1), sizeof(pcc_rule_t) * (set->len - (i + 1)));
	return PCC_TRUE;
}

static void pcc_rule_set__clear(pcc_auxil_t auxil, pcc_rule_set_t * set)
{
	set->len = 0;
}

static void pcc_rule_set__copy(pcc_auxil_t auxil, pcc_rule_set_t * set, const pcc_rule_set_t * src)
{
	size_t i;
	pcc_rule_set__clear(auxil, set);
	for (i = 0; i < src->len; i++) {
		pcc_rule_set__add(auxil, set, src->buf[i]);
	}
}

static void pcc_rule_set__term(pcc_auxil_t auxil, pcc_rule_set_t * set)
{
	PCC_FREE(auxil, set->buf);
}

static pcc_lr_head_t *pcc_lr_head__create(pcc_auxil_t auxil, pcc_rule_t rule)
{
	pcc_lr_head_t *const head = (pcc_lr_head_t *) PCC_MALLOC(auxil, sizeof(pcc_lr_head_t));
	head->rule = rule;
	pcc_rule_set__init(auxil, &head->invol, PCC_ARRAYSIZE);
	pcc_rule_set__init(auxil, &head->eval, PCC_ARRAYSIZE);
	head->hold = NULL;
	return head;
}

static void pcc_lr_head__destroy(pcc_auxil_t auxil, pcc_lr_head_t * head)
{
	if (head == NULL)
		return;
	pcc_lr_head__destroy(auxil, head->hold);
	pcc_rule_set__term(auxil, &head->eval);
	pcc_rule_set__term(auxil, &head->invol);
	PCC_FREE(auxil, head);
}

static void pcc_lr_entry__destroy(pcc_auxil_t auxil, pcc_lr_entry_t * lr);

static pcc_lr_answer_t *pcc_lr_answer__create(pcc_auxil_t auxil, pcc_lr_answer_type_t type, size_t pos)
{
	pcc_lr_answer_t *answer = (pcc_lr_answer_t *) PCC_MALLOC(auxil, sizeof(pcc_lr_answer_t));
	answer->type = type;
	answer->pos = pos;
	answer->hold = NULL;
	switch (answer->type) {
	case PCC_LR_ANSWER_LR:
		answer->data.lr = NULL;
		break;
	case PCC_LR_ANSWER_CHUNK:
		answer->data.chunk = NULL;
		break;
	default:		/* unknown */
		PCC_FREE(auxil, answer);
		answer = NULL;
	}
	return answer;
}

static void pcc_lr_answer__set_chunk(pcc_auxil_t auxil, pcc_lr_answer_t * answer, pcc_thunk_chunk_t * chunk)
{
	pcc_lr_answer_t *const a = pcc_lr_answer__create(auxil, answer->type, answer->pos);
	switch (answer->type) {
	case PCC_LR_ANSWER_LR:
		a->data.lr = answer->data.lr;
		break;
	case PCC_LR_ANSWER_CHUNK:
		a->data.chunk = answer->data.chunk;
		break;
	default:		/* unknown */
		break;
	}
	a->hold = answer->hold;
	answer->hold = a;
	answer->type = PCC_LR_ANSWER_CHUNK;
	answer->data.chunk = chunk;
}

static void pcc_lr_answer__destroy(pcc_auxil_t auxil, pcc_lr_answer_t * answer)
{
	if (answer == NULL)
		return;
	pcc_lr_answer__destroy(auxil, answer->hold);
	switch (answer->type) {
	case PCC_LR_ANSWER_LR:
		pcc_lr_entry__destroy(auxil, answer->data.lr);
		break;
	case PCC_LR_ANSWER_CHUNK:
		pcc_thunk_chunk__destroy(auxil, answer->data.chunk);
		break;
	default:		/* unknown */
		break;
	}
	PCC_FREE(auxil, answer);
}

static void pcc_lr_memo_map__init(pcc_auxil_t auxil, pcc_lr_memo_map_t * map, size_t max)
{
	map->len = 0;
	map->max = max;
	map->buf = (pcc_lr_memo_t *) PCC_MALLOC(auxil, sizeof(pcc_lr_memo_t) * map->max);
}

static size_t pcc_lr_memo_map__index(pcc_auxil_t auxil, pcc_lr_memo_map_t * map, pcc_rule_t rule)
{
	size_t i;
	for (i = 0; i < map->len; i++) {
		if (map->buf[i].rule == rule)
			return i;
	}
	return VOID_VALUE;
}

static void pcc_lr_memo_map__put(pcc_auxil_t auxil, pcc_lr_memo_map_t * map, pcc_rule_t rule, pcc_lr_answer_t * answer)
{
	const size_t i = pcc_lr_memo_map__index(auxil, map, rule);
	if (i != VOID_VALUE) {
		pcc_lr_answer__destroy(auxil, map->buf[i].answer);
		map->buf[i].answer = answer;
	} else {
		if (map->max <= map->len) {
			const size_t n = map->len + 1;
			size_t m = map->max;
			if (m == 0)
				m = 1;
			while (m < n && m != 0)
				m <<= 1;
			if (m == 0)
				m = n;
			map->buf = (pcc_lr_memo_t *) PCC_REALLOC(auxil, map->buf, sizeof(pcc_lr_memo_t) * m);
			map->max = m;
		}
		map->buf[map->len].rule = rule;
		map->buf[map->len].answer = answer;
		map->len++;
	}
}

static pcc_lr_answer_t *pcc_lr_memo_map__get(pcc_auxil_t auxil, pcc_lr_memo_map_t * map, pcc_rule_t rule)
{
	const size_t i = pcc_lr_memo_map__index(auxil, map, rule);
	return (i != VOID_VALUE) ? map->buf[i].answer : NULL;
}

static void pcc_lr_memo_map__term(pcc_auxil_t auxil, pcc_lr_memo_map_t * map)
{
	while (map->len > 0) {
		map->len--;
		pcc_lr_answer__destroy(auxil, map->buf[map->len].answer);
	}
	PCC_FREE(auxil, map->buf);
}

static pcc_lr_table_entry_t *pcc_lr_table_entry__create(pcc_auxil_t auxil)
{
	pcc_lr_table_entry_t *const entry = (pcc_lr_table_entry_t *) PCC_MALLOC(auxil, sizeof(pcc_lr_table_entry_t));
	entry->head = NULL;
	pcc_lr_memo_map__init(auxil, &entry->memos, PCC_ARRAYSIZE);
	entry->hold_a = NULL;
	entry->hold_h = NULL;
	return entry;
}

static void pcc_lr_table_entry__destroy(pcc_auxil_t auxil, pcc_lr_table_entry_t * entry)
{
	if (entry == NULL)
		return;
	pcc_lr_head__destroy(auxil, entry->hold_h);
	pcc_lr_answer__destroy(auxil, entry->hold_a);
	pcc_lr_memo_map__term(auxil, &entry->memos);
	PCC_FREE(auxil, entry);
}

static void pcc_lr_table__init(pcc_auxil_t auxil, pcc_lr_table_t * table, size_t max)
{
	table->len = 0;
	table->max = max;
	table->buf = (pcc_lr_table_entry_t **) PCC_MALLOC(auxil, sizeof(pcc_lr_table_entry_t *) * table->max);
}

static void pcc_lr_table__resize(pcc_auxil_t auxil, pcc_lr_table_t * table, size_t len)
{
	size_t i;
	for (i = len; i < table->len; i++)
		pcc_lr_table_entry__destroy(auxil, table->buf[i]);
	if (table->max < len) {
		size_t m = table->max;
		if (m == 0)
			m = 1;
		while (m < len && m != 0)
			m <<= 1;
		if (m == 0)
			m = len;
		table->buf = (pcc_lr_table_entry_t **) PCC_REALLOC(auxil, table->buf, sizeof(pcc_lr_table_entry_t *) * m);
		table->max = m;
	}
	for (i = table->len; i < len; i++)
		table->buf[i] = NULL;
	table->len = len;
}

static void pcc_lr_table__set_head(pcc_auxil_t auxil, pcc_lr_table_t * table, size_t index, pcc_lr_head_t * head)
{
	if (index >= table->len)
		pcc_lr_table__resize(auxil, table, index + 1);
	if (table->buf[index] == NULL)
		table->buf[index] = pcc_lr_table_entry__create(auxil);
	table->buf[index]->head = head;
}

static void pcc_lr_table__hold_head(pcc_auxil_t auxil, pcc_lr_table_t * table, size_t index, pcc_lr_head_t * head)
{
	if (index >= table->len)
		pcc_lr_table__resize(auxil, table, index + 1);
	if (table->buf[index] == NULL)
		table->buf[index] = pcc_lr_table_entry__create(auxil);
	head->hold = table->buf[index]->hold_h;
	table->buf[index]->hold_h = head;
}

static void pcc_lr_table__set_answer(pcc_auxil_t auxil, pcc_lr_table_t * table, size_t index, pcc_rule_t rule,
				     pcc_lr_answer_t * answer)
{
	if (index >= table->len)
		pcc_lr_table__resize(auxil, table, index + 1);
	if (table->buf[index] == NULL)
		table->buf[index] = pcc_lr_table_entry__create(auxil);
	pcc_lr_memo_map__put(auxil, &table->buf[index]->memos, rule, answer);
}

static void pcc_lr_table__hold_answer(pcc_auxil_t auxil, pcc_lr_table_t * table, size_t index, pcc_lr_answer_t * answer)
{
	if (index >= table->len)
		pcc_lr_table__resize(auxil, table, index + 1);
	if (table->buf[index] == NULL)
		table->buf[index] = pcc_lr_table_entry__create(auxil);
	answer->hold = table->buf[index]->hold_a;
	table->buf[index]->hold_a = answer;
}

static pcc_lr_head_t *pcc_lr_table__get_head(pcc_auxil_t auxil, pcc_lr_table_t * table, size_t index)
{
	if (index >= table->len || table->buf[index] == NULL)
		return NULL;
	return table->buf[index]->head;
}

static pcc_lr_answer_t *pcc_lr_table__get_answer(pcc_auxil_t auxil, pcc_lr_table_t * table, size_t index, pcc_rule_t rule)
{
	if (index >= table->len || table->buf[index] == NULL)
		return NULL;
	return pcc_lr_memo_map__get(auxil, &table->buf[index]->memos, rule);
}

static void pcc_lr_table__shift(pcc_auxil_t auxil, pcc_lr_table_t * table, size_t count)
{
	size_t i;
	if (count > table->len)
		count = table->len;
	for (i = 0; i < count; i++)
		pcc_lr_table_entry__destroy(auxil, table->buf[i]);
	memmove(table->buf, table->buf + count, sizeof(pcc_lr_table_entry_t *) * (table->len - count));
	table->len -= count;
}

static void pcc_lr_table__term(pcc_auxil_t auxil, pcc_lr_table_t * table)
{
	while (table->len > 0) {
		table->len--;
		pcc_lr_table_entry__destroy(auxil, table->buf[table->len]);
	}
	PCC_FREE(auxil, table->buf);
}

static pcc_lr_entry_t *pcc_lr_entry__create(pcc_auxil_t auxil, pcc_rule_t rule)
{
	pcc_lr_entry_t *const lr = (pcc_lr_entry_t *) PCC_MALLOC(auxil, sizeof(pcc_lr_entry_t));
	lr->rule = rule;
	lr->seed = NULL;
	lr->head = NULL;
	return lr;
}

static void pcc_lr_entry__destroy(pcc_auxil_t auxil, pcc_lr_entry_t * lr)
{
	PCC_FREE(auxil, lr);
}

static void pcc_lr_stack__init(pcc_auxil_t auxil, pcc_lr_stack_t * stack, size_t max)
{
	stack->len = 0;
	stack->max = max;
	stack->buf = (pcc_lr_entry_t **) PCC_MALLOC(auxil, sizeof(pcc_lr_entry_t *) * stack->max);
}

static void pcc_lr_stack__push(pcc_auxil_t auxil, pcc_lr_stack_t * stack, pcc_lr_entry_t * lr)
{
	if (stack->max <= stack->len) {
		const size_t n = stack->len + 1;
		size_t m = stack->max;
		if (m == 0)
			m = 1;
		while (m < n && m != 0)
			m <<= 1;
		if (m == 0)
			m = n;
		stack->buf = (pcc_lr_entry_t **) PCC_REALLOC(auxil, stack->buf, sizeof(pcc_lr_entry_t *) * m);
		stack->max = m;
	}
	stack->buf[stack->len++] = lr;
}

static pcc_lr_entry_t *pcc_lr_stack__pop(pcc_auxil_t auxil, pcc_lr_stack_t * stack)
{
	return stack->buf[--stack->len];
}

static void pcc_lr_stack__term(pcc_auxil_t auxil, pcc_lr_stack_t * stack)
{
	PCC_FREE(auxil, stack->buf);
}

static gml_context_t *pcc_context__create(pcc_auxil_t auxil)
{
	gml_context_t *const ctx = (gml_context_t *) PCC_MALLOC(auxil, sizeof(gml_context_t));
	ctx->pos = 0;
	ctx->cur = 0;
	ctx->level = 0;
	pcc_char_array__init(auxil, &ctx->buffer, PCC_BUFFERSIZE);
	pcc_lr_table__init(auxil, &ctx->lrtable, PCC_BUFFERSIZE);
	pcc_lr_stack__init(auxil, &ctx->lrstack, PCC_ARRAYSIZE);
	ctx->auxil = auxil;
	return ctx;
}

static void pcc_context__destroy(gml_context_t * ctx)
{
	if (ctx == NULL)
		return;
	pcc_lr_stack__term(ctx->auxil, &ctx->lrstack);
	pcc_lr_table__term(ctx->auxil, &ctx->lrtable);
	pcc_char_array__term(ctx->auxil, &ctx->buffer);
	PCC_FREE(ctx->auxil, ctx);
}

static size_t pcc_refill_buffer(gml_context_t * ctx, size_t num)
{
	if (ctx->buffer.len >= ctx->cur + num)
		return ctx->buffer.len - ctx->cur;
	while (ctx->buffer.len < ctx->cur + num) {
		const int c = PCC_GETCHAR(ctx->auxil);
		if (c == EOF)
			break;
		pcc_char_array__add(ctx->auxil, &ctx->buffer, (char)c);
	}
	return ctx->buffer.len - ctx->cur;
}

static void pcc_commit_buffer(gml_context_t * ctx)
{
	memmove(ctx->buffer.buf, ctx->buffer.buf + ctx->cur, ctx->buffer.len - ctx->cur);
	ctx->buffer.len -= ctx->cur;
	ctx->pos += ctx->cur;
	pcc_lr_table__shift(ctx->auxil, &ctx->lrtable, ctx->cur);
	ctx->cur = 0;
}

static const char *pcc_get_capture_string(gml_context_t * ctx, const pcc_capture_t * capt)
{
	if (capt->string == NULL)
		((pcc_capture_t *) capt)->string =
		    pcc_strndup_e(ctx->auxil, ctx->buffer.buf + capt->range.start, capt->range.end - capt->range.start);
	return capt->string;
}

static size_t pcc_get_char_as_utf32(gml_context_t * ctx, int *out)
{				/* with checking UTF-8 validity */
	int c, u;
	size_t n;
	if (pcc_refill_buffer(ctx, 1) < 1)
		return 0;
	c = (int)(unsigned char)ctx->buffer.buf[ctx->cur];
	n = (c < 0x80) ? 1 : ((c & 0xe0) == 0xc0) ? 2 : ((c & 0xf0) == 0xe0) ? 3 : ((c & 0xf8) == 0xf0) ? 4 : 0;
	if (n < 1)
		return 0;
	if (pcc_refill_buffer(ctx, n) < n)
		return 0;
	switch (n) {
	case 1:
		u = c;
		break;
	case 2:
		u = c & 0x1f;
		c = (int)(unsigned char)ctx->buffer.buf[ctx->cur + 1];
		if ((c & 0xc0) != 0x80)
			return 0;
		u <<= 6;
		u |= c & 0x3f;
		if (u < 0x80)
			return 0;
		break;
	case 3:
		u = c & 0x0f;
		c = (int)(unsigned char)ctx->buffer.buf[ctx->cur + 1];
		if ((c & 0xc0) != 0x80)
			return 0;
		u <<= 6;
		u |= c & 0x3f;
		c = (int)(unsigned char)ctx->buffer.buf[ctx->cur + 2];
		if ((c & 0xc0) != 0x80)
			return 0;
		u <<= 6;
		u |= c & 0x3f;
		if (u < 0x800)
			return 0;
		break;
	case 4:
		u = c & 0x07;
		c = (int)(unsigned char)ctx->buffer.buf[ctx->cur + 1];
		if ((c & 0xc0) != 0x80)
			return 0;
		u <<= 6;
		u |= c & 0x3f;
		c = (int)(unsigned char)ctx->buffer.buf[ctx->cur + 2];
		if ((c & 0xc0) != 0x80)
			return 0;
		u <<= 6;
		u |= c & 0x3f;
		c = (int)(unsigned char)ctx->buffer.buf[ctx->cur + 3];
		if ((c & 0xc0) != 0x80)
			return 0;
		u <<= 6;
		u |= c & 0x3f;
		if (u < 0x10000 || u > 0x10ffff)
			return 0;
		break;
	default:
		return 0;
	}
	if (out)
		*out = u;
	return n;
}

static pcc_bool_t pcc_apply_rule(gml_context_t * ctx, pcc_rule_t rule, pcc_thunk_array_t * thunks, pcc_value_t * value)
{
	static pcc_value_t null;
	pcc_thunk_chunk_t *c = NULL;
	const size_t p = ctx->pos + ctx->cur;
	pcc_bool_t b = PCC_TRUE;
	pcc_lr_answer_t *a = pcc_lr_table__get_answer(ctx->auxil, &ctx->lrtable, p, rule);
	pcc_lr_head_t *h = pcc_lr_table__get_head(ctx->auxil, &ctx->lrtable, p);
	if (h != NULL) {
		if (a == NULL && rule != h->rule && pcc_rule_set__index(ctx->auxil, &h->invol, rule) == VOID_VALUE) {
			b = PCC_FALSE;
			c = NULL;
		} else if (pcc_rule_set__remove(ctx->auxil, &h->eval, rule)) {
			b = PCC_FALSE;
			c = rule(ctx);
			a = pcc_lr_answer__create(ctx->auxil, PCC_LR_ANSWER_CHUNK, ctx->pos + ctx->cur);
			a->data.chunk = c;
			pcc_lr_table__hold_answer(ctx->auxil, &ctx->lrtable, p, a);
		}
	}
	if (b) {
		if (a != NULL) {
			ctx->cur = a->pos - ctx->pos;
			switch (a->type) {
			case PCC_LR_ANSWER_LR:
				if (a->data.lr->head == NULL) {
					a->data.lr->head = pcc_lr_head__create(ctx->auxil, rule);
					pcc_lr_table__hold_head(ctx->auxil, &ctx->lrtable, p, a->data.lr->head);
				}
				{
					size_t i = ctx->lrstack.len;
					while (i > 0) {
						i--;
						if (ctx->lrstack.buf[i]->head == a->data.lr->head)
							break;
						ctx->lrstack.buf[i]->head = a->data.lr->head;
						pcc_rule_set__add(ctx->auxil, &a->data.lr->head->invol, ctx->lrstack.buf[i]->rule);
					}
				}
				c = a->data.lr->seed;
				break;
			case PCC_LR_ANSWER_CHUNK:
				c = a->data.chunk;
				break;
			default:	/* unknown */
				break;
			}
		} else {
			pcc_lr_entry_t *const e = pcc_lr_entry__create(ctx->auxil, rule);
			pcc_lr_stack__push(ctx->auxil, &ctx->lrstack, e);
			a = pcc_lr_answer__create(ctx->auxil, PCC_LR_ANSWER_LR, p);
			a->data.lr = e;
			pcc_lr_table__set_answer(ctx->auxil, &ctx->lrtable, p, rule, a);
			c = rule(ctx);
			pcc_lr_stack__pop(ctx->auxil, &ctx->lrstack);
			a->pos = ctx->pos + ctx->cur;
			if (e->head == NULL) {
				pcc_lr_answer__set_chunk(ctx->auxil, a, c);
			} else {
				e->seed = c;
				h = a->data.lr->head;
				if (h->rule != rule) {
					c = a->data.lr->seed;
					a = pcc_lr_answer__create(ctx->auxil, PCC_LR_ANSWER_CHUNK, ctx->pos + ctx->cur);
					a->data.chunk = c;
					pcc_lr_table__hold_answer(ctx->auxil, &ctx->lrtable, p, a);
				} else {
					pcc_lr_answer__set_chunk(ctx->auxil, a, a->data.lr->seed);
					if (a->data.chunk == NULL) {
						c = NULL;
					} else {
						pcc_lr_table__set_head(ctx->auxil, &ctx->lrtable, p, h);
						for (;;) {
							ctx->cur = p - ctx->pos;
							pcc_rule_set__copy(ctx->auxil, &h->eval, &h->invol);
							c = rule(ctx);
							if (c == NULL || ctx->pos + ctx->cur <= a->pos)
								break;
							pcc_lr_answer__set_chunk(ctx->auxil, a, c);
							a->pos = ctx->pos + ctx->cur;
						}
						pcc_thunk_chunk__destroy(ctx->auxil, c);
						pcc_lr_table__set_head(ctx->auxil, &ctx->lrtable, p, NULL);
						ctx->cur = a->pos - ctx->pos;
						c = a->data.chunk;
					}
				}
			}
		}
	}
	if (c == NULL)
		return PCC_FALSE;
	if (value == NULL)
		value = &null;
	memset(value, 0, sizeof(pcc_value_t));	/* in case */
	pcc_thunk_array__add(ctx->auxil, thunks, pcc_thunk__create_node(ctx->auxil, &c->thunks, value));
	return PCC_TRUE;
}

static void pcc_do_action(gml_context_t * ctx, const pcc_thunk_array_t * thunks, pcc_value_t * value)
{
	size_t i;
	for (i = 0; i < thunks->len; i++) {
		pcc_thunk_t *const thunk = thunks->buf[i];
		switch (thunk->type) {
		case PCC_THUNK_LEAF:
			thunk->data.leaf.action(ctx, thunk, value);
			break;
		case PCC_THUNK_NODE:
			pcc_do_action(ctx, thunk->data.node.thunks, thunk->data.node.value);
			break;
		default:	/* unknown */
			break;
		}
	}
}

static void pcc_action_some_items_0(gml_context_t * __pcc_ctx, pcc_thunk_t * __pcc_in, pcc_value_t * __pcc_out)
{
#define auxil (__pcc_ctx->auxil)
#define __ (*__pcc_out)
#define left (*__pcc_in->data.leaf.values.buf[0])
#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
#define _0s ((const size_t)__pcc_in->data.leaf.capt0.range.start)
#define _0e ((const size_t)__pcc_in->data.leaf.capt0.range.end)
	ind++;
	start(ind, left);
#undef _0e
#undef _0s
#undef _0
#undef left
#undef __
#undef auxil
}

static void pcc_action_some_items_1(gml_context_t * __pcc_ctx, pcc_thunk_t * __pcc_in, pcc_value_t * __pcc_out)
{
#define auxil (__pcc_ctx->auxil)
#define __ (*__pcc_out)
#define left (*__pcc_in->data.leaf.values.buf[0])
#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
#define _0s ((const size_t)__pcc_in->data.leaf.capt0.range.start)
#define _0e ((const size_t)__pcc_in->data.leaf.capt0.range.end)
	fin(ind);
	if (ind > 0) {
		ind--;
	} else {
		ind = 0;
	}
#undef _0e
#undef _0s
#undef _0
#undef left
#undef __
#undef auxil
}

static void pcc_action_pair_0(gml_context_t * __pcc_ctx, pcc_thunk_t * __pcc_in, pcc_value_t * __pcc_out)
{
#define auxil (__pcc_ctx->auxil)
#define __ (*__pcc_out)
#define left (*__pcc_in->data.leaf.values.buf[0])
#define right (*__pcc_in->data.leaf.values.buf[1])
#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
#define _0s ((const size_t)__pcc_in->data.leaf.capt0.range.start)
#define _0e ((const size_t)__pcc_in->data.leaf.capt0.range.end)
	pair_is(left, right, ind);
#undef _0e
#undef _0s
#undef _0
#undef right
#undef left
#undef __
#undef auxil
}

static void pcc_action_pair_1(gml_context_t * __pcc_ctx, pcc_thunk_t * __pcc_in, pcc_value_t * __pcc_out)
{
#define auxil (__pcc_ctx->auxil)
#define __ (*__pcc_out)
#define left (*__pcc_in->data.leaf.values.buf[0])
#define right (*__pcc_in->data.leaf.values.buf[1])
#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
#define _0s ((const size_t)__pcc_in->data.leaf.capt0.range.start)
#define _0e ((const size_t)__pcc_in->data.leaf.capt0.range.end)
	pair_ii(left, right, ind);
#undef _0e
#undef _0s
#undef _0
#undef right
#undef left
#undef __
#undef auxil
}

static void pcc_action_pair_2(gml_context_t * __pcc_ctx, pcc_thunk_t * __pcc_in, pcc_value_t * __pcc_out)
{
#define auxil (__pcc_ctx->auxil)
#define __ (*__pcc_out)
#define left (*__pcc_in->data.leaf.values.buf[0])
#define right (*__pcc_in->data.leaf.values.buf[1])
#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
#define _0s ((const size_t)__pcc_in->data.leaf.capt0.range.start)
#define _0e ((const size_t)__pcc_in->data.leaf.capt0.range.end)
	pair_if(left, right, ind);
#undef _0e
#undef _0s
#undef _0
#undef right
#undef left
#undef __
#undef auxil
}

static void pcc_action_pair_3(gml_context_t * __pcc_ctx, pcc_thunk_t * __pcc_in, pcc_value_t * __pcc_out)
{
#define auxil (__pcc_ctx->auxil)
#define __ (*__pcc_out)
#define left (*__pcc_in->data.leaf.values.buf[0])
#define right (*__pcc_in->data.leaf.values.buf[1])
#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
#define _0s ((const size_t)__pcc_in->data.leaf.capt0.range.start)
#define _0e ((const size_t)__pcc_in->data.leaf.capt0.range.end)
	pair_id(left, right, ind);
#undef _0e
#undef _0s
#undef _0
#undef right
#undef left
#undef __
#undef auxil
}

static void pcc_action_digit_0(gml_context_t * __pcc_ctx, pcc_thunk_t * __pcc_in, pcc_value_t * __pcc_out)
{
#define auxil (__pcc_ctx->auxil)
#define __ (*__pcc_out)
#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
#define _0s ((const size_t)__pcc_in->data.leaf.capt0.range.start)
#define _0e ((const size_t)__pcc_in->data.leaf.capt0.range.end)
	__ = uniqstr((char *)_0);
#undef _0e
#undef _0s
#undef _0
#undef __
#undef auxil
}

static void pcc_action_fpnum_0(gml_context_t * __pcc_ctx, pcc_thunk_t * __pcc_in, pcc_value_t * __pcc_out)
{
#define auxil (__pcc_ctx->auxil)
#define __ (*__pcc_out)
#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
#define _0s ((const size_t)__pcc_in->data.leaf.capt0.range.start)
#define _0e ((const size_t)__pcc_in->data.leaf.capt0.range.end)
	__ = uniqstr((char *)_0);
#undef _0e
#undef _0s
#undef _0
#undef __
#undef auxil
}

static void pcc_action_id_0(gml_context_t * __pcc_ctx, pcc_thunk_t * __pcc_in, pcc_value_t * __pcc_out)
{
#define auxil (__pcc_ctx->auxil)
#define __ (*__pcc_out)
#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
#define _0s ((const size_t)__pcc_in->data.leaf.capt0.range.start)
#define _0e ((const size_t)__pcc_in->data.leaf.capt0.range.end)
#define _1 pcc_get_capture_string(__pcc_ctx, __pcc_in->data.leaf.capts.buf[0])
#define _1s ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capts.buf[0]->range.start))
#define _1e ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capts.buf[0]->range.end))
	__ = uniqstr((char *)_0);
#undef _1e
#undef _1s
#undef _1
#undef _0e
#undef _0s
#undef _0
#undef __
#undef auxil
}

static void pcc_action_string_0(gml_context_t * __pcc_ctx, pcc_thunk_t * __pcc_in, pcc_value_t * __pcc_out)
{
#define auxil (__pcc_ctx->auxil)
#define __ (*__pcc_out)
#define m (*__pcc_in->data.leaf.values.buf[0])
#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
#define _0s ((const size_t)__pcc_in->data.leaf.capt0.range.start)
#define _0e ((const size_t)__pcc_in->data.leaf.capt0.range.end)
	__ = m;
#undef _0e
#undef _0s
#undef _0
#undef m
#undef __
#undef auxil
}

static void pcc_action_mid_0(gml_context_t * __pcc_ctx, pcc_thunk_t * __pcc_in, pcc_value_t * __pcc_out)
{
#define auxil (__pcc_ctx->auxil)
#define __ (*__pcc_out)
#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
#define _0s ((const size_t)__pcc_in->data.leaf.capt0.range.start)
#define _0e ((const size_t)__pcc_in->data.leaf.capt0.range.end)
	__ = uniqstr((char *)_0);
#undef _0e
#undef _0s
#undef _0
#undef __
#undef auxil
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_file(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_head(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_list(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_some_items(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_list2(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_pair(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_digit(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_fpnum(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_id(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_string(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_mid(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_char(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule__(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_space(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_comment(gml_context_t * ctx);
static pcc_thunk_chunk_t *pcc_evaluate_rule_endofline(gml_context_t * ctx);

static pcc_thunk_chunk_t *pcc_evaluate_rule_file(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "file", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
		goto L0000;
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule_head, &chunk->thunks, NULL))
		goto L0000;
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
		goto L0000;
	if (pcc_refill_buffer(ctx, 5) < 5 ||
	    (ctx->buffer.buf + ctx->cur)[0] != 'g' ||
	    (ctx->buffer.buf + ctx->cur)[1] != 'r' ||
	    (ctx->buffer.buf + ctx->cur)[2] != 'a' ||
	    (ctx->buffer.buf + ctx->cur)[3] != 'p' || (ctx->buffer.buf + ctx->cur)[4] != 'h')
		goto L0000;
	ctx->cur += 5;
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
		goto L0000;
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule_list, &chunk->thunks, NULL))
		goto L0000;
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
		goto L0000;
	{
		const size_t p = ctx->cur;
		const size_t n = chunk->thunks.len;
		{
			int u;
			const size_t nn = pcc_get_char_as_utf32(ctx, &u);
			if (nn == 0)
				goto L0001;
			ctx->cur += nn;
		}
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		goto L0000;
L0001:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "file", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "file", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_head(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "head", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	{
		int i;
		for (i = 0;; i++) {
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			if (!pcc_apply_rule(ctx, pcc_evaluate_rule_pair, &chunk->thunks, NULL))
				goto L0001;
			if (ctx->cur == p)
				break;
			continue;
L0001:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			break;
		}
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "head", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_list(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "list", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '[')
		goto L0000;
	ctx->cur++;
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
		goto L0000;
	{
		int i;
		for (i = 0;; i++) {
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			if (!pcc_apply_rule(ctx, pcc_evaluate_rule_some_items, &chunk->thunks, NULL))
				goto L0001;
			if (ctx->cur == p)
				break;
			continue;
L0001:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			break;
		}
	}
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
		goto L0000;
	if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != ']')
		goto L0000;
	ctx->cur++;
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
		goto L0000;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "list", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "list", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_some_items(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "some_items", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos),
		  (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 1);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	{
		const size_t p = ctx->cur;
		const size_t n = chunk->thunks.len;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_id, &chunk->thunks, &(chunk->values.buf[0])))
			goto L0002;
		{
			pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_some_items_0, 1, 0);
			thunk->data.leaf.values.buf[0] = &(chunk->values.buf[0]);
			thunk->data.leaf.capt0.range.start = chunk->pos;
			thunk->data.leaf.capt0.range.end = ctx->cur;
			pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
		}
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
			goto L0002;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_list2, &chunk->thunks, NULL))
			goto L0002;
		{
			pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_some_items_1, 1, 0);
			thunk->data.leaf.values.buf[0] = &(chunk->values.buf[0]);
			thunk->data.leaf.capt0.range.start = chunk->pos;
			thunk->data.leaf.capt0.range.end = ctx->cur;
			pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
		}
		goto L0001;
L0002:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_pair, &chunk->thunks, NULL))
			goto L0003;
		goto L0001;
L0003:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		goto L0000;
L0001:		;
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "some_items", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "some_items", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_list2(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "list2", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos),
		  (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '[')
		goto L0000;
	ctx->cur++;
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
		goto L0000;
	{
		int i;
		for (i = 0;; i++) {
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			if (!pcc_apply_rule(ctx, pcc_evaluate_rule_some_items, &chunk->thunks, NULL))
				goto L0001;
			if (ctx->cur == p)
				break;
			continue;
L0001:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			break;
		}
	}
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
		goto L0000;
	if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != ']')
		goto L0000;
	ctx->cur++;
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
		goto L0000;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "list2", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "list2", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_pair(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "pair", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 2);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	{
		const size_t p = ctx->cur;
		const size_t n = chunk->thunks.len;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_id, &chunk->thunks, &(chunk->values.buf[0])))
			goto L0002;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
			goto L0002;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_string, &chunk->thunks, &(chunk->values.buf[1])))
			goto L0002;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
			goto L0002;
		{
			pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_pair_0, 2, 0);
			thunk->data.leaf.values.buf[0] = &(chunk->values.buf[0]);
			thunk->data.leaf.values.buf[1] = &(chunk->values.buf[1]);
			thunk->data.leaf.capt0.range.start = chunk->pos;
			thunk->data.leaf.capt0.range.end = ctx->cur;
			pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
		}
		goto L0001;
L0002:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_id, &chunk->thunks, &(chunk->values.buf[0])))
			goto L0003;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
			goto L0003;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_id, &chunk->thunks, &(chunk->values.buf[1])))
			goto L0003;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
			goto L0003;
		{
			pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_pair_1, 2, 0);
			thunk->data.leaf.values.buf[0] = &(chunk->values.buf[0]);
			thunk->data.leaf.values.buf[1] = &(chunk->values.buf[1]);
			thunk->data.leaf.capt0.range.start = chunk->pos;
			thunk->data.leaf.capt0.range.end = ctx->cur;
			pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
		}
		goto L0001;
L0003:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_id, &chunk->thunks, &(chunk->values.buf[0])))
			goto L0004;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
			goto L0004;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_fpnum, &chunk->thunks, &(chunk->values.buf[1])))
			goto L0004;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
			goto L0004;
		{
			pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_pair_2, 2, 0);
			thunk->data.leaf.values.buf[0] = &(chunk->values.buf[0]);
			thunk->data.leaf.values.buf[1] = &(chunk->values.buf[1]);
			thunk->data.leaf.capt0.range.start = chunk->pos;
			thunk->data.leaf.capt0.range.end = ctx->cur;
			pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
		}
		goto L0001;
L0004:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_id, &chunk->thunks, &(chunk->values.buf[0])))
			goto L0005;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
			goto L0005;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_digit, &chunk->thunks, &(chunk->values.buf[1])))
			goto L0005;
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL))
			goto L0005;
		{
			pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_pair_3, 2, 0);
			thunk->data.leaf.values.buf[0] = &(chunk->values.buf[0]);
			thunk->data.leaf.values.buf[1] = &(chunk->values.buf[1]);
			thunk->data.leaf.capt0.range.start = chunk->pos;
			thunk->data.leaf.capt0.range.end = ctx->cur;
			pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
		}
		goto L0001;
L0005:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		goto L0000;
L0001:		;
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "pair", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "pair", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_digit(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "digit", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos),
		  (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	{
		const size_t p = ctx->cur;
		const size_t n = chunk->thunks.len;
		{
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '-')
				goto L0003;
			ctx->cur++;
			goto L0002;
L0003:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '+')
				goto L0004;
			ctx->cur++;
			goto L0002;
L0004:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			goto L0001;
L0002:			;
		}
		goto L0005;
L0001:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
L0005:		;
	}
	{
		const size_t p0 = ctx->cur;
		const size_t n0 = chunk->thunks.len;
		int i;
		for (i = 0;; i++) {
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			{
				int u;
				const size_t nn = pcc_get_char_as_utf32(ctx, &u);
				if (nn == 0)
					goto L0006;
				if (!((u >= 0x000030 && u <= 0x000039)
				    ))
					goto L0006;
				ctx->cur += nn;
			}
			if (ctx->cur == p)
				break;
			continue;
L0006:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			break;
		}
		if (i < 1) {
			ctx->cur = p0;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n0);
			goto L0000;
		}
	}
	{
		pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_digit_0, 0, 0);
		thunk->data.leaf.capt0.range.start = chunk->pos;
		thunk->data.leaf.capt0.range.end = ctx->cur;
		pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "digit", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "digit", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_fpnum(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "fpnum", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos),
		  (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	{
		const size_t p = ctx->cur;
		const size_t n = chunk->thunks.len;
		{
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '-')
				goto L0003;
			ctx->cur++;
			goto L0002;
L0003:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '+')
				goto L0004;
			ctx->cur++;
			goto L0002;
L0004:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			goto L0001;
L0002:			;
		}
		goto L0005;
L0001:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
L0005:		;
	}
	{
		int i;
		for (i = 0;; i++) {
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			{
				int u;
				const size_t nn = pcc_get_char_as_utf32(ctx, &u);
				if (nn == 0)
					goto L0006;
				if (!((u >= 0x000030 && u <= 0x000039)
				    ))
					goto L0006;
				ctx->cur += nn;
			}
			if (ctx->cur == p)
				break;
			continue;
L0006:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			break;
		}
	}
	if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '.')
		goto L0000;
	ctx->cur++;
	{
		const size_t p0 = ctx->cur;
		const size_t n0 = chunk->thunks.len;
		int i;
		for (i = 0;; i++) {
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			{
				int u;
				const size_t nn = pcc_get_char_as_utf32(ctx, &u);
				if (nn == 0)
					goto L0007;
				if (!((u >= 0x000030 && u <= 0x000039)
				    ))
					goto L0007;
				ctx->cur += nn;
			}
			if (ctx->cur == p)
				break;
			continue;
L0007:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			break;
		}
		if (i < 1) {
			ctx->cur = p0;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n0);
			goto L0000;
		}
	}
	{
		const size_t p = ctx->cur;
		const size_t n = chunk->thunks.len;
		{
			int u;
			const size_t nn = pcc_get_char_as_utf32(ctx, &u);
			if (nn == 0)
				goto L0008;
			if (!(u == 0x000027 || u == 0x000065 || u == 0x000027 || u == 0x000027 || u == 0x000045 || u == 0x000027))
				goto L0008;
			ctx->cur += nn;
		}
		{
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			{
				const size_t p = ctx->cur;
				const size_t n = chunk->thunks.len;
				if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '-')
					goto L0011;
				ctx->cur++;
				goto L0010;
L0011:				;
				ctx->cur = p;
				pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
				if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '+')
					goto L0012;
				ctx->cur++;
				goto L0010;
L0012:				;
				ctx->cur = p;
				pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
				goto L0009;
L0010:				;
			}
			goto L0013;
L0009:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
L0013:			;
		}
		{
			const size_t p0 = ctx->cur;
			const size_t n0 = chunk->thunks.len;
			int i;
			for (i = 0;; i++) {
				const size_t p = ctx->cur;
				const size_t n = chunk->thunks.len;
				{
					int u;
					const size_t nn = pcc_get_char_as_utf32(ctx, &u);
					if (nn == 0)
						goto L0014;
					if (!((u >= 0x000030 && u <= 0x000039)
					    ))
						goto L0014;
					ctx->cur += nn;
				}
				if (ctx->cur == p)
					break;
				continue;
L0014:				;
				ctx->cur = p;
				pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
				break;
			}
			if (i < 1) {
				ctx->cur = p0;
				pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n0);
				goto L0008;
			}
		}
		goto L0015;
L0008:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
L0015:		;
	}
	{
		pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_fpnum_0, 0, 0);
		thunk->data.leaf.capt0.range.start = chunk->pos;
		thunk->data.leaf.capt0.range.end = ctx->cur;
		pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "fpnum", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "fpnum", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_id(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "id", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 1);
	{
		const size_t p = ctx->cur;
		size_t q;
		{
			const size_t p0 = ctx->cur;
			const size_t n0 = chunk->thunks.len;
			int i;
			for (i = 0;; i++) {
				const size_t p = ctx->cur;
				const size_t n = chunk->thunks.len;
				{
					int u;
					const size_t nn = pcc_get_char_as_utf32(ctx, &u);
					if (nn == 0)
						goto L0001;
					if (!((u >= 0x000061 && u <= 0x00007a) ||
					      (u >= 0x000041 && u <= 0x00005a) || u == 0x00005f))
						goto L0001;
					ctx->cur += nn;
				}
				if (ctx->cur == p)
					break;
				continue;
L0001:				;
				ctx->cur = p;
				pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
				break;
			}
			if (i < 1) {
				ctx->cur = p0;
				pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n0);
				goto L0000;
			}
		}
		{
			int i;
			for (i = 0;; i++) {
				const size_t p = ctx->cur;
				const size_t n = chunk->thunks.len;
				{
					int u;
					const size_t nn = pcc_get_char_as_utf32(ctx, &u);
					if (nn == 0)
						goto L0002;
					if (!((u >= 0x000061 && u <= 0x00007a) ||
					      (u >= 0x000041 && u <= 0x00005a) || u == 0x00005f || (u >= 0x000030 && u <= 0x000039)
					    ))
						goto L0002;
					ctx->cur += nn;
				}
				if (ctx->cur == p)
					break;
				continue;
L0002:				;
				ctx->cur = p;
				pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
				break;
			}
		}
		q = ctx->cur;
		chunk->capts.buf[0].range.start = p;
		chunk->capts.buf[0].range.end = q;
	}
	{
		pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_id_0, 0, 1);
		thunk->data.leaf.capts.buf[0] = &(chunk->capts.buf[0]);
		thunk->data.leaf.capt0.range.start = chunk->pos;
		thunk->data.leaf.capt0.range.end = ctx->cur;
		pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "id", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "id", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_string(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "string", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos),
		  (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 1);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\"')
		goto L0000;
	ctx->cur++;
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule_mid, &chunk->thunks, &(chunk->values.buf[0])))
		goto L0000;
	if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\"')
		goto L0000;
	ctx->cur++;
	{
		pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_string_0, 1, 0);
		thunk->data.leaf.values.buf[0] = &(chunk->values.buf[0]);
		thunk->data.leaf.capt0.range.start = chunk->pos;
		thunk->data.leaf.capt0.range.end = ctx->cur;
		pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "string", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "string", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_mid(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "mid", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	{
		int i;
		for (i = 0;; i++) {
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			if (!pcc_apply_rule(ctx, pcc_evaluate_rule_char, &chunk->thunks, NULL))
				goto L0001;
			if (ctx->cur == p)
				break;
			continue;
L0001:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			break;
		}
	}
	{
		pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_mid_0, 0, 0);
		thunk->data.leaf.capt0.range.start = chunk->pos;
		thunk->data.leaf.capt0.range.end = ctx->cur;
		pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "mid", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_char(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "char", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	{
		const size_t p = ctx->cur;
		const size_t n = chunk->thunks.len;
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\\')
			goto L0002;
		ctx->cur++;
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\"')
			goto L0002;
		ctx->cur++;
		goto L0001;
L0002:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\\')
			goto L0003;
		ctx->cur++;
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\\')
			goto L0003;
		ctx->cur++;
		goto L0001;
L0003:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\\')
			goto L0004;
		ctx->cur++;
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != 'b')
			goto L0004;
		ctx->cur++;
		goto L0001;
L0004:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\\')
			goto L0005;
		ctx->cur++;
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != 'f')
			goto L0005;
		ctx->cur++;
		goto L0001;
L0005:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\\')
			goto L0006;
		ctx->cur++;
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != 'n')
			goto L0006;
		ctx->cur++;
		goto L0001;
L0006:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\\')
			goto L0007;
		ctx->cur++;
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != 'r')
			goto L0007;
		ctx->cur++;
		goto L0001;
L0007:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\\')
			goto L0008;
		ctx->cur++;
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != 't')
			goto L0008;
		ctx->cur++;
		goto L0001;
L0008:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		{
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\"')
				goto L0010;
			ctx->cur++;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			goto L0009;
L0010:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		}
		{
			int u;
			const size_t nn = pcc_get_char_as_utf32(ctx, &u);
			if (nn == 0)
				goto L0009;
			ctx->cur += nn;
		}
		goto L0001;
L0009:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		goto L0000;
L0001:		;
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "char", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "char", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule__(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "_", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	{
		int i;
		for (i = 0;; i++) {
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			{
				const size_t p = ctx->cur;
				const size_t n = chunk->thunks.len;
				if (!pcc_apply_rule(ctx, pcc_evaluate_rule_space, &chunk->thunks, NULL))
					goto L0003;
				goto L0002;
L0003:				;
				ctx->cur = p;
				pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
				if (!pcc_apply_rule(ctx, pcc_evaluate_rule_comment, &chunk->thunks, NULL))
					goto L0004;
				goto L0002;
L0004:				;
				ctx->cur = p;
				pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
				goto L0001;
L0002:				;
			}
			if (ctx->cur == p)
				break;
			continue;
L0001:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			break;
		}
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "_", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_space(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "space", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos),
		  (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	{
		const size_t p = ctx->cur;
		const size_t n = chunk->thunks.len;
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != ' ')
			goto L0002;
		ctx->cur++;
		goto L0001;
L0002:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\t')
			goto L0003;
		ctx->cur++;
		goto L0001;
L0003:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (!pcc_apply_rule(ctx, pcc_evaluate_rule_endofline, &chunk->thunks, NULL))
			goto L0004;
		goto L0001;
L0004:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		goto L0000;
L0001:		;
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "space", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "space", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_comment(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "comment", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos),
		  (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '#')
		goto L0000;
	ctx->cur++;
	{
		int i;
		for (i = 0;; i++) {
			const size_t p = ctx->cur;
			const size_t n = chunk->thunks.len;
			{
				const size_t p = ctx->cur;
				const size_t n = chunk->thunks.len;
				if (!pcc_apply_rule(ctx, pcc_evaluate_rule_endofline, &chunk->thunks, NULL))
					goto L0002;
				ctx->cur = p;
				pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
				goto L0001;
L0002:				;
				ctx->cur = p;
				pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			}
			{
				int u;
				const size_t nn = pcc_get_char_as_utf32(ctx, &u);
				if (nn == 0)
					goto L0001;
				ctx->cur += nn;
			}
			if (ctx->cur == p)
				break;
			continue;
L0001:			;
			ctx->cur = p;
			pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
			break;
		}
	}
	if (!pcc_apply_rule(ctx, pcc_evaluate_rule_endofline, &chunk->thunks, NULL))
		goto L0000;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "comment", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "comment", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

static pcc_thunk_chunk_t *pcc_evaluate_rule_endofline(gml_context_t * ctx)
{
	pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx->auxil);
	chunk->pos = ctx->cur;
	PCC_DEBUG(PCC_DBG_EVALUATE, "endofline", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos),
		  (ctx->buffer.len - chunk->pos));
	ctx->level++;
	pcc_value_table__resize(ctx->auxil, &chunk->values, 0);
	pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0);
	{
		const size_t p = ctx->cur;
		const size_t n = chunk->thunks.len;
		if (pcc_refill_buffer(ctx, 2) < 2 ||
		    (ctx->buffer.buf + ctx->cur)[0] != '\r' || (ctx->buffer.buf + ctx->cur)[1] != '\n')
			goto L0002;
		ctx->cur += 2;
		goto L0001;
L0002:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (pcc_refill_buffer(ctx, 2) < 2 ||
		    (ctx->buffer.buf + ctx->cur)[0] != '\n' || (ctx->buffer.buf + ctx->cur)[1] != '\r')
			goto L0003;
		ctx->cur += 2;
		goto L0001;
L0003:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\n')
			goto L0004;
		ctx->cur++;
		goto L0001;
L0004:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		if (pcc_refill_buffer(ctx, 1) < 1 || ctx->buffer.buf[ctx->cur] != '\r')
			goto L0005;
		ctx->cur++;
		goto L0001;
L0005:		;
		ctx->cur = p;
		pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
		goto L0000;
L0001:		;
	}
	ctx->level--;
	PCC_DEBUG(PCC_DBG_MATCH, "endofline", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	return chunk;
L0000:	;
	ctx->level--;
	PCC_DEBUG(PCC_DBG_NOMATCH, "endofline", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos));
	pcc_thunk_chunk__destroy(ctx->auxil, chunk);
	return NULL;
}

gml_context_t *gml_create(void *auxil)
{
	return pcc_context__create(auxil);
}

int gml_parse(gml_context_t * ctx, char **ret)
{
	pcc_thunk_array_t thunks;
	pcc_thunk_array__init(ctx->auxil, &thunks, PCC_ARRAYSIZE);
	if (pcc_apply_rule(ctx, pcc_evaluate_rule_file, &thunks, ret))
		pcc_do_action(ctx, &thunks, ret);
	else
		PCC_ERROR(ctx->auxil);
	pcc_commit_buffer(ctx);
	pcc_thunk_array__term(ctx->auxil, &thunks);
	return pcc_refill_buffer(ctx, 1) >= 1;
}

void gml_destroy(gml_context_t * ctx)
{
	pcc_context__destroy(ctx);
}

/* parse, return 0 if oke, or >0 the line number of parse error */
/* adding data to raw node/edge lists */
int gmlparse(struct usrgraph *mg, FILE * stream, char *name, int debug)
{
	gml_context_t *ctx = NULL;
	int ret = 0;
	if (mg == NULL) {
		return (1);
	}
	maing = mg;
	ctx = gml_create(NULL);
	linenr = 1;
	ind = 0;
	parseerror = 0;
	pdebug = debug;
	if (name) {
		pname = name;
	} else {
		pname = "unknown";
	}
	if (stream) {
		curstream = stream;
	} else {
		curstream = stdin;
	}
	while (gml_parse(ctx, NULL)) {;
	}
	gml_destroy(ctx);
	if (parseerror) {
		ret = linenr;
	} else {
		/* no parse error */
		ret = 0;
	}
	return (ret);
}

/* end. */
